﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using wrsm.battlenet.entity;

namespace wrsm.client {

    /// <summary>
    /// Main UI Form
    /// </summary>
    public partial class MainForm : Form {

        #region [Local Attributes]

        /// <summary>
        /// Realm Status Monitor
        /// </summary>
        private RealmStatusMonitor _monitor;

        /// <summary>
        /// Realm Status Change, Notification Manager
        /// </summary>
        private RealmStatusChangeNotificationManager _statusChagnedNotifyManager;

        #endregion

        #region [UI Update Delegates]

        /// <summary>
        /// Delegate used to update realm status
        /// </summary>
        private RealmStatusHandler _updateRealmStatusDelegate;

        /// <summary>
        /// Delegate used to update realm status pull... status...
        /// </summary>
        private StringHandler _updateRealmStatusPullStatus;

        #endregion

        #region [Construction]

        /// <summary>
        /// Initialize Main Form
        /// </summary>
        public MainForm() {
            InitializeComponent();
        }

        /// <summary>
        /// Initialize Main Form
        /// </summary>
        /// <param name="monitor">Active Realm Status Montor</param>
        internal MainForm(RealmStatusMonitor monitor) : this() {
            _monitor = monitor;
            _statusChagnedNotifyManager = new RealmStatusChangeNotificationManager();
        }

        #endregion

        #region [Form Events]

        /// <summary>
        /// Fires when form loads
        /// </summary>
        private void OnFormLoad(object sender, EventArgs e) {
            //Create empty display filters
            _displayFilter = CreateFilters();
            
            //Wireup UI Delegates, monitor and notify manager
            WireupUIDelegates();
            WireupStatusMonitorEvents();
            WireupNotificationManagerEvents();

            //Restore Saved Realm Status
            _monitor.RestoreSavedRealmData();
        }

        /// <summary>
        /// Fires when user selects Update Realm Status From File Menu
        /// </summary>
        private void updateRealmStatusToolStripMenuItem_Click(object sender, EventArgs e) {
            _monitor.UpdateRealmStatus();
        }

        #endregion

        #region [Realm Status Monitor Events]

        /// <summary>
        /// Wires up all events used from status monitor
        /// </summary>
        private void WireupStatusMonitorEvents() {
            _monitor.RealmStatusChanged += new RealmStatusHandler(OnRealmStatusChanged);
            _monitor.RealmStatusPullRequested += new GeneralHandler(OnRealmStatusPullRequested);
            _monitor.RealmStatusPullCompleted += new GeneralHandler(OnRealmStatusPullCompleted);
            _monitor.RealmStatusPullFaulted += new GeneralHandler(OnRealmStatusPullFaulted);
        }

        /// <summary>
        /// Fires when the Realm Status Montor detects a change to one of the realms
        /// </summary>
        /// <param name="status">realm status</param>
        private void OnRealmStatusChanged(RealmStatus status) {
            this.Invoke(_updateRealmStatusDelegate, new object[] { status });
        }

        /// <summary>
        /// Fires when Realm Status Pull starts
        /// </summary>
        private void OnRealmStatusPullRequested() {
            this.Invoke(_updateRealmStatusPullStatus, new object[] { "Requesting" });
        }

        /// <summary>
        /// Fires when Realm Status Pull Completes
        /// </summary>
        private void OnRealmStatusPullCompleted() {
            this.Invoke(_updateRealmStatusPullStatus, new object[] { "Complete" });
        }

        /// <summary>
        /// Fires when Realm Status Pull Faults
        /// </summary>
        private void OnRealmStatusPullFaulted() {
            this.Invoke(_updateRealmStatusPullStatus, new object[] { "Failed" });
        }

        #endregion

        #region [Realm Status Change Notification Manager Events]

        /// <summary>
        /// Wire's up Notification manager Events
        /// </summary>
        private void WireupNotificationManagerEvents() {
            _statusChagnedNotifyManager.RealmStatusChangedNotification += new RealmStatusHandler(OnRealmStatusChangedNotification);
        }

        /// <summary>
        /// Fires when the realm statys change, requires a UI notification
        /// </summary>
        /// <param name="status">Realm Status Change, to notify user about</param>
        void OnRealmStatusChangedNotification(RealmStatus status) {
            notifyIcon.BalloonTipTitle = "Realm Status Changed";
            notifyIcon.BalloonTipText = string.Format("{0} is now {1}!", status.Name, status.Status ? "Up" : "Down");
            notifyIcon.ShowBalloonTip(1000);
        }

        #endregion

        #region [Form Physics]

        /// <summary>
        /// Wire up UI delegates
        /// </summary>
        private void WireupUIDelegates() {
            _updateRealmStatusDelegate += new RealmStatusHandler(UpdateRealmStatus);
            _updateRealmStatusPullStatus += new StringHandler(UpdateRealmPullStatusBar);
        }

        /// <summary>
        /// Updates Status bar, to show the state of the current or last realm status pull
        /// </summary>
        /// <param name="status">text to display in the status bar</param>
        private void UpdateRealmPullStatusBar(string status) {
            tlsRequestStatus.Text = status;
        }

        /// <summary>
        /// Updates all required UI elements to indicate a status update for a realm
        /// </summary>
        /// <param name="status">realm status to render</param>
        private void UpdateRealmStatus(RealmStatus status) {
            //Update List
            UpdateRealmStatusInList(status);
            //Queue this status change, to be notified to the user
            if (!_monitor.RestoreMode) {
                //Don't queue up the nofifications if we're just restoring realm status's
                _statusChagnedNotifyManager.AddStatus(status);
            }
        }

        /// <summary>
        /// Updates the ListView to reflect the latest status for the realm
        /// </summary>
        /// <param name="status">Realm status to update</param>
        private void UpdateRealmStatusInList(RealmStatus status) {
            //no point in updating if this doesn't work with the filter
            if (!FilterAllowsRealmToDisplay(status)) {
                return;
            }

            //Attempt to locate the realm in the list
            ListViewItem item = null;
            foreach (ListViewItem i in lstvRealmStatus.Items) {
                if (((RealmStatus)i.Tag).Name == status.Name.Trim()) {
                    item = i;
                    item.Tag = status;
                    item.Text = status.Status ? "Up" : "Down";
                }
            }
            //If the realm cannot be located in the list, create it
            if (item == null) {
                item = AddRealmStatusToList(status);
            }
            //Select/highlight the item
            item.Selected = true;
        }

        /// <summary>
        /// Add Realm Status to list
        /// </summary>
        /// <param name="status">realm status to add to list</param>
        private ListViewItem AddRealmStatusToList(RealmStatus status) {
            ListViewItem item = new ListViewItem(new string[] { 
				     status.Status ? "Up" : "Down",
				     status.Name,
				     status.Type,
				     status.Population,
				     status.Locale}
                );
            item.Tag = status;
            lstvRealmStatus.Items.Add(item);
            return item;
        }

        /// <summary>
        /// Refresh realm status List, with Realm status values in monitor
        /// </summary>
        private void RefreshRealmStatusList() {
            //Clear the list
            lstvRealmStatus.Items.Clear();
            foreach (RealmStatus status in _monitor.GetAllRealmStatus()) {
                //If filter will allow the item to display, we should display it
                if (FilterAllowsRealmToDisplay(status)) {
                    AddRealmStatusToList(status);
                }
            }
        }

        #endregion

        #region [Display Filter]

        /// <summary>
        /// Contains the display filters, which are used when filling out the form
        /// </summary>
        private Dictionary<string, string> _displayFilter;

        /// <summary>
        /// Creates the initial display filters, with default settings
        /// </summary>
        /// <returns>empty display filters</returns>
        private Dictionary<string, string> CreateFilters() {
            Dictionary<string, string> displayFilter = new Dictionary<string, string>();
            displayFilter["name"] = string.Empty;
            displayFilter["status"] = "all";
            displayFilter["type"] = "all";
            return displayFilter;
        }

        /// <summary>
        /// Fires when user changes text in the name filter
        /// </summary>
        private void txtNameFilter_TextChanged(object sender, EventArgs e) {
            TextBox tbox = (TextBox)sender;
            _displayFilter["name"] = string.IsNullOrEmpty(tbox.Text) ? string.Empty : tbox.Text;
            //Refresh the list to reflect filters
            RefreshRealmStatusList();
        }

        /// <summary>
        /// Fires when the user changes any radio button selection for status display filter
        /// </summary>
        private void OnStatusFilterCheckedChanged(object sender, EventArgs e) {
            RadioButton rbn = (RadioButton)sender;
            if (rbn.Checked == true) {
                _displayFilter["status"] = GetRbnFilterValue(rbn);
            }
            //Refresh the list to reflect filters
            RefreshRealmStatusList();
        }

        /// <summary>
        /// Fires when the user changes any radio button selection for type display filter
        /// </summary>
        private void OnTypeFilterCheckedChanged(object sender, EventArgs e) {
            RadioButton rbn = (RadioButton)sender;
            if (rbn.Checked == true) {
                _displayFilter["type"] = GetRbnFilterValue(rbn);
            }
            //Refresh the list to reflect filters
            RefreshRealmStatusList();
        }

        /// <summary>
        /// Extracts the filter Value for the radio button
        /// </summary>
        /// <param name="rbn">Radio Button to get filter value for</param>
        /// <returns>filter value</returns>
        private string GetRbnFilterValue(RadioButton rbn) {
            return rbn.Tag as string;
        }

        /// <summary>
        /// A simple check to see if the filter is too restricting to show status
        /// </summary>
        /// <param name="status">Realm Status to check</param>
        /// <returns>true if status should be shown, otherwise false</returns>
        private bool FilterAllowsRealmToDisplay(RealmStatus status) {
            //Verify that the name works with the filter
            if (!status.Name.ToLower().Contains(_displayFilter["name"].ToLower().Trim()))
                return false;
            //If the 'all' status flag is up, we wont check this filter
            if (_displayFilter["status"] != "all") {
                //Otherwise, if the status is set to show up, make sure we only allow realms with an 'up' status
                if (status.Status && _displayFilter["status"] != "up") {
                    return false;
                } else if (!status.Status && _displayFilter["status"] != "down") {
                    return false;
                }
            }
            //If the 'all' type flag is up, we wont check this filter
            if (_displayFilter["type"] != "all") {
                //only allow realms with the same type selected
                if (status.Type != _displayFilter["type"])
                    return false;
            }

            //Allow realms that pass the filter checks
            return true;
        }

        #endregion

        #region [Notify Icon and Notify Context Menu]

        /// <summary>
        /// fires when user selects Show/Hide from context menu on notify icon
        /// </summary>
        private void toggleMainForm_Click(object sender, EventArgs e) {
            Visible = !Visible;
        }

        /// <summary>
        /// Fires when user double clicks on the notify icon
        /// </summary>
        private void notifyIcon_DoubleClick(object sender, EventArgs e) {
            Visible = !Visible;
        }

        #endregion

    }
}
